/*
 * app_led.c
 *
 *  Created on: 2023年7月14日
 *      Author: zlw
 */

#include "app_led.h"
#include "app_log.h"
#include "bsp_pca9555.h"

static led_ins_t ledTaskCach = {0};
static led_ins_t ledTaskRun = {0};

static bool ledState = false;

ds_gpio_t redDrive = {0};
ds_gpio_t greenDrive = {0};
ds_gpio_t blueDrive = {0};

bool ledStateGet(void)
{
  return ledState;
}

/**
 * @brief: led blink timer callback
 * */
static void ledBlinkTimerCallback(MultiTimer* timer, void* userData)
{
  led_ins_t *ledDrive = (led_ins_t *)userData;
  (void)timer;

  if((ledDrive->bitMaskRed >> ledDrive->bitOffset) & 0x01)
      ds_gpio_on(ledDrive->ledRed);
  else
      ds_gpio_off(ledDrive->ledRed);
  if((ledDrive->bitMaskGreen >> ledDrive->bitOffset) & 0x01)
    ds_gpio_on(ledDrive->ledGreen);
  else
    ds_gpio_off(ledDrive->ledGreen);
  if((ledDrive->bitMaskBlue >> ledDrive->bitOffset) & 0x01)
    ds_gpio_on(ledDrive->ledBlue);
  else
    ds_gpio_off(ledDrive->ledBlue);

  ledDrive->bitOffset  = ((ledDrive->bitOffset) + 1) % 8;

  if(ledDrive->bitOffset == 0 && ledDrive->blinkCycleTotal > 0 && ledDrive->blinkCycleTotal != 0xFF)
    ledDrive->blinkCycleTotal --;

  if(ledDrive->blinkCycleTotal > 0) {
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, ledDrive->timer, ledDrive->bitTimes*BIT_MAST_TIMER_UNIT, ledDrive->callbackFun, ledDrive, 1);
  }
  else {
      ds_gpio_off(ledDrive->ledRed);
      ds_gpio_off(ledDrive->ledGreen);
      ds_gpio_off(ledDrive->ledBlue);
      if(ledTaskCach.blinkCycleTotal > 0) {
          memset(&ledTaskRun, 0, sizeof(led_ins_t));
          memcpy(&ledTaskRun, &ledTaskCach, sizeof(led_ins_t));
          memset(&ledTaskCach, 0, sizeof(led_ins_t));
          softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, ledTaskRun.timer, ledTaskRun.bitTimes*BIT_MAST_TIMER_UNIT, ledTaskRun.callbackFun, &ledTaskRun, 0);
      }
      else {
          led_blink_finist_callback(ledTaskRun.type);
          ledState = false;
          memset(&ledTaskCach, 0, sizeof(led_ins_t));
          memset(&ledTaskRun, 0, sizeof(led_ins_t));
      }
  }
}

__WEAK void led_blink_finist_callback(blinkType_t type)
{
  (void)type;
}

/**
 * @brief: led_ins_t 结构体初始化
 * @param: ledDriver:led_ins_t 结构体指针
 * @param: timer:定时器指针
 * @param: 绿灯结构体对象
 * @param： 橙色灯结构体对象
 * @param： 红灯结构体对象
 * @param： 灯物模型//data[0]:green bitmask;data[1]orange bitmask;data[2]red bitmask;data[3]循环周期;data[4] bit 时间
 * */
void led_driver_init(led_ins_t *ledDrive, MultiTimer* timer, ds_gpio_t ledRed, ds_gpio_t ledGreen, ds_gpio_t ledBlue,  uint8_t *data, blinkType_t type)
{
  redDrive = ledRed;
  greenDrive = ledGreen;
  blueDrive = ledBlue;

  if(ledTaskRun.type == REG_SUCCESS_BLINK && ledDrive->type != REGIEST_BLINK) {
      return ;
  }
  if(type == NONE_BLINK) {
      ledState = false;
      softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, timer, 0);
      ds_gpio_off(ledDrive->ledRed);
      ds_gpio_off(ledDrive->ledGreen);
      ds_gpio_off(ledDrive->ledBlue);
      memset(&ledTaskCach, 0, sizeof(led_ins_t));
      memset(&ledTaskRun, 0, sizeof(led_ins_t));
      return ;
  }

#if defined(SM_SMART_PLUG)
  (void)ledRed;
  (void)ledGreen;
  ledDrive->ledRed = NULL;
  ledDrive->ledGreen = NULL;
#else
  ledDrive->ledRed = &redDrive;
  ledDrive->ledGreen = &greenDrive;
#endif
  ledDrive->ledBlue = &blueDrive;
  ledDrive->bitMaskRed = data[0];
  ledDrive->bitMaskGreen = data[1];
  ledDrive->bitMaskBlue = data[2];
  ledDrive->bitTimes = data[3] + 1;
  ledDrive->blinkCycleTotal = data[4];
  ledDrive->bitOffset = 0;
  ledDrive->type = type;
  ledDrive->timer = timer;
  ledDrive->callbackFun = ledBlinkTimerCallback;

  ledState = true;
  if(timer->status == EN_MULTITIMER_STATUS_IDLE) {
      memcpy(&ledTaskRun, ledDrive, sizeof(led_ins_t));
      ds_gpio_init(ledTaskRun.ledRed);
      ds_gpio_init(ledTaskRun.ledGreen);
      ds_gpio_init(ledTaskRun.ledBlue);
      ledBlinkTimerCallback(timer, &ledTaskRun);
  }
  else {
      if(ledTaskRun.type == ALARM_BLINK) {
          memcpy(&ledTaskCach, ledDrive, sizeof(led_ins_t));
      }
      else if((ledDrive->type == ALARM_BLINK || ledDrive->type == LED_MODEL_BLINK) &&
          (ledTaskRun.type == REGIEST_BLINK || ledTaskRun.type == FIND_ME_BLINK)) {
          softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, timer, 0);
          memcpy(&ledTaskCach, &ledTaskRun, sizeof(led_ins_t));
          memcpy(&ledTaskRun, ledDrive, sizeof(led_ins_t));
          ledBlinkTimerCallback(timer, &ledTaskRun);
      }
      else if(ledDrive->type == REGIEST_BLINK || ledDrive->type == REG_SUCCESS_BLINK
          || (ledDrive->type == LED_MODEL_BLINK && ledTaskRun.type == LED_MODEL_BLINK)) {
          softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, timer, 0);
          memcpy(&ledTaskRun, ledDrive, sizeof(led_ins_t));
          memset(&ledTaskCach, 0, sizeof(led_ins_t));
          ledBlinkTimerCallback(timer, &ledTaskRun);
      }
#if defined(SM_KF)
      else if(ledDrive->type == ALARM_BLINK && ledTaskRun.type == LED_MODEL_BLINK) {
          softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, timer, 0);
          memcpy(&ledTaskRun, ledDrive, sizeof(led_ins_t));
          memset(&ledTaskCach, 0, sizeof(led_ins_t));
          ledBlinkTimerCallback(timer, &ledTaskRun);
      }
#endif
  }
}

/************************keyPad led driver*********************************************/

static uint8_t pLedData[2] = {0x00};
static bool pca9555Write = false;

void pca9555WriteStateSet(bool state)
{
  pca9555Write = state;
}

void keyPad_led_on(keyPadLed_t led)
{
  if(led < BAT_CTRL) {
      pLedData[0] &= ~(0x01 << led);
  }
  else if (led > FAULT_ORANGE && led < ALL_GPIO) {
      pLedData[1] &= ~(0x01 << (led % 8));
  }
  else {
      pLedData[0] = 0x06;
      pLedData[1] = 0x0E;
  }
  pca9555Write = true;
}

void keyPad_led_off(keyPadLed_t led)
{
  if(led < BAT_CTRL) {
      pLedData[0] |= (0x01 << led);
  }
  else if (led > FAULT_ORANGE && led < ALL_GPIO) {
      pLedData[1] |= (0x01 << (led % 8));
  }
  else {
      pLedData[0] = 0xFF;
      pLedData[1] = 0xFF;
  }
  pca9555Write = true;
}

void keyPad_led_send(void)
{
  if(pca9555Write == true) {
      pca9555Write = false;
      pca9555_gpio_out(pLedData);
  }
}

/************************keyPad signal led blink*********************************************/

keypad_signal_led_t signalLedRun = {0x00};

static void keyPadSignalLedBlinkTimerCallback(MultiTimer* timer, void* userData)
{
  keypad_signal_led_t *keyPadLed = (keypad_signal_led_t *)userData;
  (void)timer;

  if((keyPadLed->bitMaskRed >> keyPadLed->bitOffset) & 0x01)
    keyPad_led_on(SIGNAL_RED);
  else
    keyPad_led_off(SIGNAL_RED);
  if((keyPadLed->bitMaskGreen >> keyPadLed->bitOffset) & 0x01)
    keyPad_led_on(SIGNAL_GREEN);
  else
    keyPad_led_off(SIGNAL_GREEN);
  if((keyPadLed->bitMaskBlue >> keyPadLed->bitOffset) & 0x01)
    keyPad_led_on(SIGNAL_ORANGE);
  else
    keyPad_led_off(SIGNAL_ORANGE);


  keyPadLed->bitOffset  = ((keyPadLed->bitOffset) + 1) % 8;

  if(keyPadLed->bitOffset == 0)
    keyPadLed->blinkCycleOffset ++;

  if(keyPadLed->blinkCycleTotal == 0xFF || (keyPadLed->blinkCycleOffset < keyPadLed->blinkCycleTotal)) {
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, keyPadLed->timer, keyPadLed->bitTimes*BIT_MAST_TIMER_UNIT, keyPadLed->callbackFun, keyPadLed, 0);
  }
  else {
      keyPad_led_off(SIGNAL_RED);
      keyPad_led_off(SIGNAL_GREEN);
      keyPad_led_off(SIGNAL_ORANGE);
      memset(&signalLedRun, 0, sizeof(keypad_signal_led_t));
  }
}

static void keypad_signal_led_blink_start(keypad_signal_led_t *keyPadLed)
{
  if(keyPadLed->bitMaskRed == 0 && keyPadLed->bitMaskGreen == 0 && keyPadLed->bitMaskBlue == 0) {
      keyPad_led_off(SIGNAL_RED);
      keyPad_led_off(SIGNAL_GREEN);
      keyPad_led_off(SIGNAL_ORANGE);
      softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, keyPadLed->timer, 0);
  }
  else {
      if((keyPadLed->bitMaskRed >> keyPadLed->bitOffset) & 0x01)
        keyPad_led_on(SIGNAL_RED);
      else
        keyPad_led_off(SIGNAL_RED);
      if((keyPadLed->bitMaskGreen >> keyPadLed->bitOffset) & 0x01)
        keyPad_led_on(SIGNAL_GREEN);
      else
        keyPad_led_off(SIGNAL_GREEN);
      if((keyPadLed->bitMaskBlue >> keyPadLed->bitOffset) & 0x01)
        keyPad_led_on(SIGNAL_ORANGE);
      else
        keyPad_led_off(SIGNAL_ORANGE);


      keyPadLed->bitOffset  = ((keyPadLed->bitOffset) + 1) % 8;

      if(keyPadLed->timer->status != EN_MULTITIMER_STATUS_IDLE)
        softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, keyPadLed->timer, 0);
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, keyPadLed->timer, keyPadLed->bitTimes*BIT_MAST_TIMER_UNIT, keyPadLed->callbackFun, keyPadLed, 0);
  }
}

void keypad_signal_led_blink_start_init(keypad_signal_led_t *keyPadLed, MultiTimer* timer, uint8_t *data, blinkType_t type)
{
  if(type == signalLedRun.type) {
      return ;
  }
  keyPadLed->bitMaskRed = data[0];
  keyPadLed->bitMaskGreen = data[1];
  keyPadLed->bitMaskBlue = data[2];
  keyPadLed->bitTimes = data[3] + 1;
  keyPadLed->blinkCycleTotal = data[4];
  keyPadLed->bitOffset = 0;
  keyPadLed->blinkCycleOffset = 0;
  keyPadLed->type = type;
  keyPadLed->timer = timer;
  keyPadLed->callbackFun = keyPadSignalLedBlinkTimerCallback;

  memcpy(&signalLedRun, keyPadLed, sizeof(keypad_signal_led_t));
  keypad_signal_led_blink_start(&signalLedRun);
}

/*********************alarm led blink*****************************************/

static void keyPadAlarmLedBlinkTimerCallback(MultiTimer* timer, void* userData)
{
  keypad_alarm_led_t *keyPadLed = (keypad_alarm_led_t *)userData;
  (void)timer;

  if((keyPadLed->bitMaskalarm >> keyPadLed->bitOffset) & 0x01)
    keyPad_led_on(ALERM_RED);
  else
    keyPad_led_off(ALERM_RED);

  keyPadLed->bitOffset  = ((keyPadLed->bitOffset) + 1) % 8;

  if(keyPadLed->bitOffset == 0)
    keyPadLed->blinkCycleOffset ++;

  if(keyPadLed->blinkCycleTotal == 0xFF || (keyPadLed->blinkCycleOffset < keyPadLed->blinkCycleTotal)) {
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, keyPadLed->timer, keyPadLed->bitTimes*BIT_MAST_TIMER_UNIT, keyPadLed->callbackFun, keyPadLed, 0);
  }
  else {
      keyPad_led_off(SIGNAL_RED);
      keyPad_led_off(SIGNAL_GREEN);
      keyPad_led_off(SIGNAL_ORANGE);
  }
}

static void keypad_alarm_led_blink_start(keypad_alarm_led_t *keyPadLed)
{
  if(keyPadLed->bitMaskalarm == 0) {
      keyPad_led_off(ALERM_RED);
      softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, keyPadLed->timer, 0);
  }
  else {
      if((keyPadLed->bitMaskalarm >> keyPadLed->bitOffset) & 0x01)
        keyPad_led_on(ALERM_RED);
      else
        keyPad_led_off(ALERM_RED);

      keyPadLed->bitOffset  = ((keyPadLed->bitOffset) + 1) % 8;

      if(keyPadLed->timer->status != EN_MULTITIMER_STATUS_IDLE)
        softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, keyPadLed->timer, 0);
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, keyPadLed->timer, keyPadLed->bitTimes*BIT_MAST_TIMER_UNIT, keyPadLed->callbackFun, keyPadLed, 0);
  }
}

void keypad_alarm_led_blink_start_init(keypad_alarm_led_t *keyPadLed, MultiTimer* timer, uint8_t *data)
{
  keyPadLed->bitMaskalarm = data[0];
  keyPadLed->bitTimes = data[1] + 1;
  keyPadLed->blinkCycleTotal = data[2];
  keyPadLed->bitOffset = 0;
  keyPadLed->blinkCycleOffset = 0;
  keyPadLed->timer = timer;
  keyPadLed->callbackFun = keyPadAlarmLedBlinkTimerCallback;

  keypad_alarm_led_blink_start(keyPadLed);
}

